#include "os_task.h"
#include "adc.h"
#include "dac.h"
#include "ds18b20.h"
#include "main.h"
#include "sdadc.h"
#include "stream.h"
#include "subctrl.h"
#include "sys.h"
#include "usart.h"
#include "usbd_cdc_if.h"

sub_control_t subctrl __attribute__((section(".bss.NoInit")));

const static adc_channel_index_t kAdcConfig[] = {
    {DL_JC1_ADC_CHANNEL, RF_JB1_ADC_CHANNEL},
    {DL_JC2_ADC_CHANNEL, RF_JB2_ADC_CHANNEL},
    {DL_JC3_ADC_CHANNEL, RF_JB3_ADC_CHANNEL},
};

const static ds18b20_config_t kTempConfig[] = {
    {PA_TEMP1_GPIO_Port, PA_TEMP1_Pin, &subctrl.pa[kModule1st].temperature},
    {PA_TEMP2_GPIO_Port, PA_TEMP2_Pin, &subctrl.pa[kModule2nd].temperature},
    {PA_TEMP3_GPIO_Port, PA_TEMP3_Pin, &subctrl.pa[kModule3rd].temperature},
};

const static pd_pin_index_t kPdConfig[] = {
    {PA_PD1_GPIO_Port, PA_PD1_Pin},
    {PA_PD2_GPIO_Port, PA_PD2_Pin},
    {PA_PD3_GPIO_Port, PA_PD3_Pin},
};

const static phase_nss_index_t kPhaseNssConfig[] = {
    {RF_PHASE1_GPIO_Port, RF_PHASE1_Pin},
    {RF_PHASE2_GPIO_Port, RF_PHASE2_Pin},
    {RF_PHASE3_GPIO_Port, RF_PHASE3_Pin},
};

const static dac_channel_index_t kDacConfig[] = {
    {&hdac1, DAC_CHANNEL_2},
    {&hdac1, DAC_CHANNEL_1},
    {&hdac2, DAC_CHANNEL_1},
};

const static pa_module_hardware_config_t kPaModuleHardwareConfig[] = {
    {&kAdcConfig[kModule1st], &kTempConfig[kModule1st], &kPdConfig[kModule1st], &kDacConfig[kModule1st],
     &kPhaseNssConfig[kModule1st]},
    {&kAdcConfig[kModule2nd], &kTempConfig[kModule2nd], &kPdConfig[kModule2nd], &kDacConfig[kModule2nd],
     &kPhaseNssConfig[kModule2nd]},
    {&kAdcConfig[kModule3rd], &kTempConfig[kModule3rd], &kPdConfig[kModule3rd], &kDacConfig[kModule3rd],
     &kPhaseNssConfig[kModule3rd]},
};

static int16_t adc_raw_data[ADC_CHANNEL_NUM] = {NULL};

StreamProcessor Serial(nullptr);
StreamProcessor RS485(&UART_RS485);
SubController SubControl(subctrl, kPaModuleHardwareConfig);

void RS485RunCallback(void *handle);
void SerialRunCallback(void *handle);
void StreamOutCallback(uint8_t *data, uint16_t size, void *handle);

void SerialTask(void *pvParameters)
{
    Serial.RegisterStreamOutCallback(StreamOutCallback);
    Serial.RegisterStreamRunCallback(SerialRunCallback);
    Log::SetOutputStream(&Serial);
    for (;;)
    {
        Serial.Run();
    }
}

void RS485Task(void *pvParameters)
{
    RS485.RegisterStreamOutCallback(StreamOutCallback);
    RS485.RegisterStreamRunCallback(RS485RunCallback);
    HAL_UARTEx_ReceiveToIdle_DMA(&UART_RS485, RS485.payload_, DEFAULT_STREAM_PAYLOAD_SIZE);
    for (;;)
    {
        RS485.Run();
    }
}

void UpdateTask(void *pvParameters)
{
    static uint8_t index = 0;
    static int16_t data_sample[ADC_SUM_NUM][ADC_CHANNEL_NUM] = {NULL};
    static float data_avg[ADC_CHANNEL_NUM] = {NULL};

    HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);
    HAL_DAC_Start(&hdac1, DAC_CHANNEL_2);
    HAL_DAC_Start(&hdac2, DAC_CHANNEL_1);

    HAL_ADCEx_Calibration_Start(&hadc1);
    HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_raw_data, 6);
    HAL_SDADC_InjectedStart_DMA(&hsdadc1, (uint32_t *)&adc_raw_data[ADC_CHANNEL_NUM - 2], 2);
    for (;;)
    {
        memcpy(data_sample[index++], adc_raw_data, sizeof(adc_raw_data));
        if (index >= ADC_SUM_NUM)
            index = 0;

        for (uint8_t i = 0; i < ADC_CHANNEL_NUM; i++)
        {
            for (uint8_t j = 0; j < ADC_SUM_NUM; j++)
            {
                data_avg[i] += data_sample[j][i];
            }
            data_avg[i] /= ADC_SUM_NUM;
        }
        /* 更新电流 检波 温度数据 */
        /*MAX4080计算公式
         * Vout=Rsense * Iload * Av
         * I = V / (0.01 * 60)*/
        for (uint8_t i = 0; i < kModuleNum; i++)
        {
            subctrl.pa[i].current = (data_avg[kPaModuleHardwareConfig[i].adc_index->current] * (3.3f / 4095)) /
                                    (SAMPLING_RESISTOR * MAX4080_GAIN);
            subctrl.pa[i].rf_wave = data_avg[kPaModuleHardwareConfig[i].adc_index->rf_wave] * (3.3f / 4095);
        }
        subctrl.rf_power.forward = data_avg[ADC_CHANNEL_NUM - 2] * (3.3f / 4095);
        subctrl.rf_power.reverse = data_avg[ADC_CHANNEL_NUM - 1] * (3.3f / 4095);
        vTaskDelay(pdMS_TO_TICKS(50));
    }
}

void AutoTask(void *pvParameters)
{
    TickType_t xLastWakeTime = xTaskGetTickCount();
    for (;;)
    {
        SubControl.ForwardLoop();
        vTaskDelay(pdMS_TO_TICKS(100));
        SubControl.ReverseLoop();
        xTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(200));
    }
}

void MainTask(void *pvParameters)
{
    TickType_t xLastWakeTime;
    xLastWakeTime = xTaskGetTickCount();
    DS18B20_Init(kTempConfig);
    for (;;)
    {
        LED_ON();
        DS18B20_GetStart();
        vTaskDelay(pdMS_TO_TICKS(500));
        DS18B20_GetTempe();
        LED_OFF();
        vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(1000));
    }
}

void InitTask(void *pvParameters)
{
    SubControl.Init(&Serial);
    xTaskCreate(UpdateTask, "UpdateTask", 256, nullptr, 3, nullptr);
    // xTaskCreate(AutoTask, "AutoTask", 256, nullptr, 2, nullptr);
    xTaskCreate(MainTask, "MainTask", 128, nullptr, 1, nullptr);
    vTaskDelete(NULL);
}

void OsTaskStartRun()
{
    xTaskCreate(SerialTask, "SerialTask", 512, nullptr, 5, nullptr);
    xTaskCreate(RS485Task, "RS485Task", 512, nullptr, 5, nullptr);
    xTaskCreate(InitTask, "InitTask", 256, nullptr, 4, nullptr);
    vTaskStartScheduler();
}

void SerialRunCallback(void *handle)
{
    if (Serial.payload_[0] == SERIAL_FRAME_HEADER)
    {
        if (ADD8_Check(Serial.payload_, Serial.size_))
        {
            Serial.Print("校验错误！\n");
            return;
        }
        switch (Serial.payload_[1])
        {
        case 0: /* 查询运行数据 */
            // clang-format off
            Serial.Print("\n编译日期: %s\n"
                         "IP地址: %d 状态: %s\n"
                         "自动运行: %s\n"
                         "复位次数: %d\n"
                         "目标功率: %d\n"
                         "正向功率: %7.2f\n"
                         "反向功率: %7.2f\n"
                         "PA序号:     1     2     3\n"
                         "PA使能:     %d     %d     %d\n"
                         "PA温度: %5.2f %5.2f %5.2f\n"
                         "PA电流: %5.2f %5.2f %5.2f\n"
                         "相位值: %5.2f %5.2f %5.2f\n"
                         "衰减值: %5.2f %5.2f %5.2f\n",
                         __DATE__,
                         subctrl.header.ip[3], SubControl.GetStatus(),
                         subctrl.state.auto_run ? "开启" : "关闭",
                         subctrl.state.soft_reset_count,
                         subctrl.rf_power.target,
                         subctrl.rf_power.forward,
                         subctrl.rf_power.reverse,
                         BIT_READ(subctrl.state.pa_enable, kModule1st),
                         BIT_READ(subctrl.state.pa_enable, kModule2nd),
                         BIT_READ(subctrl.state.pa_enable, kModule3rd),
                         subctrl.pa[kModule1st].temperature,
                         subctrl.pa[kModule2nd].temperature,
                         subctrl.pa[kModule3rd].temperature,
                         subctrl.pa[kModule1st].current,
                         subctrl.pa[kModule2nd].current,
                         subctrl.pa[kModule3rd].current,
                         subctrl.pa[kModule1st].phase,
                         subctrl.pa[kModule2nd].phase,
                         subctrl.pa[kModule3rd].phase,
                         subctrl.pa[kModule1st].attenuation,
                         subctrl.pa[kModule2nd].attenuation,
                         subctrl.pa[kModule3rd].attenuation);
            // 原始检波数据
            Serial.Print("PA检波: %5.2f %5.2f %5.2f\n",
                         subctrl.pa[kModule1st].rf_wave,
                         subctrl.pa[kModule2nd].rf_wave,
                         subctrl.pa[kModule3rd].rf_wave);
            // clang-format on
            break;
        case 1: /* 保存参数 */
            SubControl.SaveParameter();
            break;
        case 2: /* 设定功率 */
            SubControl.SetTargetPower(DataInversion(&Serial.payload_[2]).integer);
            break;
        case 3: /* 设置相位 */
            SubControl.SetPhase(DataInversion(&Serial.payload_[2]).decimal,
                                DataInversion(&Serial.payload_[2 + sizeof(float)]).decimal,
                                DataInversion(&Serial.payload_[2 + sizeof(float) * 2]).decimal);
            break;
        case 4: /* 设置衰减 */
            SubControl.SetAttenuation(DataInversion(&Serial.payload_[2]).decimal,
                                      DataInversion(&Serial.payload_[2 + sizeof(float)]).decimal,
                                      DataInversion(&Serial.payload_[2 + sizeof(float) * 2]).decimal);
            break;
        case 5: /* 设置自动运行 */
            SubControl.SetAutoRun(*(switch_state_t *)&Serial.payload_[2]);
            break;
        case 6: /* 设置ip地址 */
            SubControl.SetAddress(&Serial.payload_[2]);
            break;
        case 7:
            SubControl.SetPhase(*(uint8_t *)&Serial.payload_[2], DataInversion(&Serial.payload_[3]).integer);
            break;
        case 8: /* */
            SubControl.SetAttenuation(*(uint8_t *)&Serial.payload_[2], DataInversion(&Serial.payload_[3]).integer);
            break;
        case 255: /* 复位 */
            SubControl.Restart(Serial.payload_[2]);
            break;
        }
    }
    else
    {
        Serial.Print("数据帧错误！\n");
    }
}

void RS485RunCallback(void *handle)
{
    if (RS485.payload_[0] == RS485_FRAME_HEADER)
    {
        if (ADD8_Check(RS485.payload_, RS485.size_)) // 校验错误
            goto RS485_END;
        if (SubControl.CheckAddress(RS485.payload_[1])) // IP地址匹配
        {
            switch (RS485.payload_[2])
            {
            case RS485_TYPE_QUERY: /* 查询报文 */
                ADD8_Calculation((uint8_t *)&subctrl, sizeof(sub_control_t) - 1);
                RS485.Print((uint8_t *)&subctrl, sizeof(sub_control_t));
                break;
            case RS485_TYPE_SAVE_PARAMETER: /* 保存参数 */
                SubControl.SaveParameter();
                break;
            case RS485_TYPE_POWER: /* 设定功率 */
                SubControl.SetTargetPower(DataConversion(&RS485.payload_[3]).integer);
                break;
            case RS485_TYPE_PHASE: /* 设定相位 */
                SubControl.SetPhase(DataConversion(&RS485.payload_[3]).decimal,
                                    DataConversion(&RS485.payload_[3] + sizeof(float)).decimal,
                                    DataConversion(&RS485.payload_[3] + sizeof(float) * 2).decimal);
                break;
            case RS485_TYPE_ATTENUATION: /* 设定衰减 */
                SubControl.SetAttenuation(DataConversion(&RS485.payload_[3]).decimal,
                                          DataConversion(&RS485.payload_[3] + sizeof(float)).decimal,
                                          DataConversion(&RS485.payload_[3] + sizeof(float) * 2).decimal);
                break;
            case RS485_TYPE_AUTO_RUN: /* 设置自动运行 */
                SubControl.SetAutoRun(*(switch_state_t *)&RS485.payload_[3]);
                break;
            case RS485_TYPE_FORWAR_PID: /* 设定正向PID */
                // SubControl.SetForwardPID(*(pid_config_t *)&RS485.payload_[3]);
                break;
            case RS485_TYPE_REVERSE_PID: /* 设定反向PID */
                // SubControl.SetReversePID(*(pid_config_t *)&RS485.payload_[3]);
                break;
            }
        }
        else if (RS485.payload_[1] == SUBCTRL_BASE_ADDRESS + kSubCtrlNum) // 通用地址
        {
            switch (RS485.payload_[2])
            {
            case RS485_TYPE_SAVE_PARAMETER: /* 保存参数 */
                SubControl.SaveParameter();
                break;
            case RS485_TYPE_POWER: /* 设定功率 */
                SubControl.SetTargetPower(DataConversion(&RS485.payload_[3]).integer);
                break;
            case RS485_TYPE_PHASE: /* 设定相位 */
                if (BIT_READ(DataConversion(&RS485.payload_[3]).half[0], SubControl.GetDeviceID()))
                    SubControl.SetPhase(PA_MODULE_ALL_BIT, DataConversion(&RS485.payload_[3]).half[1]);
                break;
            case RS485_TYPE_ATTENUATION: /* 设定衰减 */
                if (BIT_READ(DataConversion(&RS485.payload_[3]).half[0], SubControl.GetDeviceID()))
                    SubControl.SetAttenuation(PA_MODULE_ALL_BIT, DataConversion(&RS485.payload_[3]).half[1]);
                break;
            case RS485_TYPE_AUTO_RUN: /* 设置自动运行 */
                SubControl.SetAutoRun(*(switch_state_t *)&RS485.payload_[3]);
                break;
            }
        }
    }
RS485_END:
    HAL_UARTEx_ReceiveToIdle_DMA((UART_HandleTypeDef *)handle, RS485.payload_, DEFAULT_STREAM_PAYLOAD_SIZE);
}

void Flash_Init(sub_control_flash_t *flash, const void *default_flash)
{
#if !ENABLE_DEBUG_MODE
    sub_control_flash_t temp;

    flash->header.init = DEFAULT_INITIAL_VALUE;
    Flash_Read(FLASH_START_ADDR, (uint32_t *)&temp, sizeof(sub_control_flash_t) / sizeof(uint32_t));
    if (temp.header.init != flash->header.init)
    {
        memcpy(flash, default_flash, sizeof(sub_control_flash_t));
        Serial.Print("已加载默认参数\n");
        if (Flash_Write(FLASH_START_ADDR, (uint32_t *)flash, sizeof(sub_control_flash_t) / sizeof(uint32_t)))
            Serial.Print("闪存初始化失败\n");
        else
            Serial.Print("闪存已初始化\n");
    }
    else
    {
        memcpy(flash, &temp, sizeof(sub_control_flash_t));
        Serial.Print("已加载闪存参数\n"
                     "IP: %3d.%3d.%3d.%3d\n",
                     flash->header.ip[0], flash->header.ip[1], flash->header.ip[2], flash->header.ip[3]);
    }
#else
    memcpy(flash, default_flash, sizeof(sub_control_flash_t));
#endif
}

void StreamOutCallback(uint8_t *data, uint16_t size, void *handle)
{
    if (handle != nullptr)
    {
        HAL_UART_Transmit_DMA((UART_HandleTypeDef *)handle, data, size);
    }
    else
    {
        CDC_Transmit_FS(data, size);
        Serial.SendComplete();
    }
}

uint8_t *CDC_GetTxBuffer()
{
    return Serial.GetOutputBuffer();
}

uint8_t *CDC_GetRxBuffer()
{
    return Serial.payload_;
}

void CDC_RecvComplete(uint16_t size)
{
    Serial.RecvComplete(size);
}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Pos)
{
    if (huart == &UART_RS485)
    {
        RS485.RecvComplete(Pos);
    }
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart == &UART_RS485)
    {
        RS485.SendComplete();
    }
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if (huart == &UART_RS485)
    {
        HAL_UARTEx_ReceiveToIdle_DMA(huart, RS485.payload_, DEFAULT_STREAM_PAYLOAD_SIZE);
    }
}